// These are meant to be typed into the REPL. You can also run
// scala -Xnojline < 12_nest.sc to run them all at once.

abstract class Item
case class Article(description: String, price: Double) extends Item
case class Bundle(description: String, discount: Double, items: Item*) extends Item

val special = Bundle("Father's day special", 20.0,
       Article("Scala for the", 39.95),
       Bundle("Anchor Distillery Sampler", 10.0,
              Article("Old Potrero Straight Rye Whiskey", 79.95),
              Article("Junípero Gin", 32.95)
       )
)

special match {
  case Bundle(_, _, Article(descr, _), _*) => descr
}
//res0: String = Scala for the

/**
 * art @ Article(_, _) 意思是匹配的 Article(_, _) 赋值给 art
 * rest @ _* 意思是将剩余的【元素数组】赋值给 reset
 *
 */
special match {
  case Bundle(_, _, art @ Article(_, _), rest @ _*) => (art, rest)
}
//res1: (Article, Seq[Item]) = (Article(Scala for the,39.95),WrappedArray(Bundle(Anchor Distillery Sampler,10.0,WrappedArray(Article(Old Potrero Straight Rye Whiskey,79.95), Article(Jun??pero Gin,32.95)))))

/**
 * art @ Article(_, _) 意思是匹配的 Article(_, _) 赋值给 art
 * rest @ _* 意思是将后面紧跟的【元素】赋值给 reset
 */
special match {
  case Bundle(_, _, art @ Article(_, _), rest) => (art, rest)
}
//res2: (Article, Item) = (Article(Scala for the,39.95),Bundle(Anchor Distillery Sampler,10.0,WrappedArray(Article(Old Potrero Straight Rye Whiskey,79.95), Article(Jun??pero Gin,32.95))))


// 计算物品价格
def price(it: Item): Double = it match {
  /**
   * 如果是 Article 类型直接返回 p
   */
  case Article(_, p) => p
  /**
   * 如果是 Bundle 类型
   * disc 是总折扣
   * its @ _* 表示剩下参数的数组
   * its.map(price _) 表示递归调用 price _ 就是参数，方法然后一直到匹配到 Article(_, p) 返回 p（price）
   */
  case Bundle(_, disc, its @ _*) => its.map(price _).sum - disc
}

price(special)

